#include <compilation/instruction/Expression.h>
#include <compilation/instruction/Instruction.h>


namespace compilation
{


bool ExpressionInstruction::isPhi() const
{ return m_expression.get() && m_expression->hasType<TPhi>(); }


void
ExpressionInstruction::print(
    std::ostream &out,
    std::function<void(void)> const& indent) const
{
  m_expression->print(out, indent);
  out << ';' << '\n';
}


void
GotoInstruction::print(
    std::ostream &out,
    std::function<void(void)> const& indent) const
{
  bool frontier_on_next_line = true;

  /**/ if (m_context == CLoop)
    out << "goto loop " << getSNextInstruction();
  else if (m_context == CAfterIfThen)
  { out << "then"; frontier_on_next_line = false; }
  else if (m_context == CAfterIfElse)
  { out << "else"; frontier_on_next_line = false; }
  else if (m_context == CBeforeLabel)
    out << "goto label " << getSNextInstruction();
  else
    out << "goto " << getSNextInstruction();

  if (!m_dominationFrontier.empty())
  {
    if (frontier_on_next_line)
    {
      out << std::endl;
      indent();
      out << ' ';
    }
    out << " -> domination frontier = { ";

    DominationFrontier::const_iterator
        iter = m_dominationFrontier.begin();

    if (iter != m_dominationFrontier.end())
    {
      out << ((*iter)->getSNextInstruction())
             ->getRegistrationIndex();
      ++iter;
    }

    for (; iter != m_dominationFrontier.end(); ++iter)
    {
      out << ", "
          << ((*iter)->getSNextInstruction())
             ->getRegistrationIndex();
    }

    out << " }";
  }

  out << '\n';
}


void
IfInstruction::print(
    std::ostream &out,
    std::function<void(void)> const& indent) const
{
  out << "if (";

  if (m_expression.get()) m_expression->print(out, indent);
  else out << "no-expr";

  out << ")\n";
}


void
ReturnInstruction::print(
    std::ostream &out,
    std::function<void(void)> const& indent) const
{
  out << "return ";
  m_result->print(out, indent);
  out << ";\n";
}


void EnterBlockInstruction::print(
    std::ostream &out,
    std::function<void(void)> const& indent) const
{
  out << '{';
  m_scope.printAsDeclarations(out, indent);
  out << '\n';
}


void LabelInstruction::print(
    std::ostream &out,
    std::function<void(void)> const& indent) const
{
  out << "label " << this << std::endl;

  if (m_dominator)
  {
    if (indent) indent();
    out << "  -> dominated by "
        << m_dominator->getRegistrationIndex()
        << ": ";
    m_dominator->print(out, indent);
  }
  else out << std::endl;

  if (!m_dominationFrontier.empty())
  {
    if (indent) indent();
    out << "  -> domination frontier = { ";

    DominationFrontier::const_iterator
        iter = m_dominationFrontier.begin();

    if (iter != m_dominationFrontier.end())
    {
      out << ((*iter)->getSNextInstruction())
             ->getRegistrationIndex();
      ++iter;
    }

    for (; iter != m_dominationFrontier.end(); ++iter)
    {
      out << ", "
          << ((*iter)->getSNextInstruction())
             ->getRegistrationIndex();
    }

    out << " }\n";
  }
}


} // compilation
